<template>
    <div id="container">
        <div id="mainContent">
            <div id="content">
                <div id="auctionBox">
                     <!-- 图片 -->
                    <div id="auction_img">
                        <img 
                        id="my_picture"
                        :src="'http://localhost:8957/commons/download?picName=' + auctionStore.auction_info.pictureName" alt="" 
                        v-if="auctionStore.auction_info.pictureName">
                    </div>
                    <!-- 当前竞拍价格 -->
                    <div id="auction_price">
                        <span id="dqj">当前价:</span>
                        <span id="dqj_price">{{ auctionStore.newPriceObj.newPrice || auctionStore.auction_info.price }}</span>
                    </div>
                    <!-- 出价 -->
                    <div id="buying_price">
                        <span id="cj">出价: </span>
                        <input type="text" id="buying_price_ipt" v-model="price" >
                    </div>
                    <!-- 竞拍按钮 -->
                    <div id="papapa">
                        <button 
                        @click="auctionHandle" 
                        :class="{notAuctionStyle:!isStartAuction, AuctionStyle:isStartAuction}"
                        >竞拍</button>
                    </div>
                </div>
                <!-- 未开拍提示 -->
                <div id="tip" v-if="auctionStore.auction_info.status != 1">竞品拍卖时间未到</div>
                <div id="tip1" v-if="auctionStore.auction_info.status == 1">
                    <img id="hotIcon" src="../assets/auctionIcon.png" alt="HOT">
                </div>
            </div>
            <!-- 回合倒计时 -->
            <div :style="{display: roundTimeShowStyle}">
                <div id="roundTimeShow">
                    <div>
                        <div style="text-align: center; font-size: 15px; color: #545353;">竞拍倒计时</div>
                        <div id="timeSecondNumber" style="text-align: center; margin-top: 10px;">{{ timeBySecond }}S</div>
                    </div>
                </div>
                
            </div>
        </div>
        <div id="right_aside" >
            <RightAside></RightAside>
        </div>
    </div>
</template>

<script setup lang="ts">
import RightAside from '../components/RightAside.vue';
import { useAuctionStore } from '../stores/auction';
import { useUserStore } from '../stores/user';
import { onMounted, inject, ref, watch } from 'vue';
import { AuctionProduct } from '../dto/AuctionProduct';
import AUctionCount from '../dto/AuctionCount';
import AuctionInfo from '../dto/AuctionInfo';
import axios from 'axios';
import { ElMessage } from 'element-plus';
import moment from 'moment';
import { MyLocalStorage } from '../myClass/MyLocalStorage';
import WebSocketService from '../myClass/WebSocketService';

axios.defaults.headers.post['Content-Type'] = 'application/json';

// 获取pinia中选择的竞品数据
const auctionStore = useAuctionStore();

// 获取pinia中选择的用户数据
const userStore = useUserStore()
// 管理拍卖倒计时定时器的列表
const auctionTimerList: NodeJS.Timeout[] = [];
// 流拍定时器（10分钟）
let notAuctionTimer: NodeJS.Timeout | undefined = undefined;
//是否开始拍卖标识
let isStartAuction = ref<Boolean>(true);
// webSocket连接对象
let mysocket:WebSocketService | null = null;
// 回合倒计时展示
// let showTime = ref<Boolean>(false);
// 回合倒计时秒数
let timeBySecond = ref<number>(0);
// 控制倒计时的display样式
let roundTimeShowStyle = ref<string>('none');
// 30秒倒计时定时器
let countDownTimer: NodeJS.Timeout | null = null;
// 请求基本路径（从全局注入）
let BASERUL: string| undefined= "";
// 用户出价
let price = ref<number>(0);

onMounted(()=>{
    // 获取所有竞品的map数据【竞品ID： 竞品拍卖时间】
    getAuctionProductMapData();
    // 获取本地存储，重新开启流拍定时器
    getLocalStorageTimeOut();
    // 连接websocket
    linkWebSocket()
    // 获取请求基本路径
    BASERUL = inject("apiBaseUrl");
    // 获取最新的出价价格
    getbuyingPrice()
})

/**
 * 设置出价价格
 */
function getbuyingPrice(){
    if(auctionStore.newPriceObj.newPrice > 0){
        price.value = parseInt(auctionStore.newPriceObj.newPrice) + parseInt(auctionStore.auction_info.incrementPrice)
    }else{
        price.value = auctionStore.auction_info.price + auctionStore.auction_info.incrementPrice;
    }
}

// 监视pinia中的状态变化（切换竞品触发）
watch(()=>auctionStore.auction_info, (newValue)=>{
    isStartAuction.value = newValue.status == 1 
    // 从redis中根据id取竞拍时间戳，判断是否需要展示倒计时（不为null或距离现在秒数 > 0）
    checkAddCountDownShow(auctionStore.auction_info)
    auctionStore.targgleAuc()
    getbuyingPrice()
},{immediate:true})

// 监视"竞拍"按钮的点击（有人点击按钮时触发）
watch(()=>auctionStore.auctionHandleFlag, (newValue)=>{
    console.log("有人竞拍·...",newValue); 
    // 监听到拍卖触发，将拍卖倒计时显示，并重置30秒回合倒计时（有人竞拍了）
    if(newValue){
        // 显示30s倒计时
        roundTimeShowStyle.value = 'block';
        // 开启定时器，30秒定时器开启
        openCountDown(30)
    }else{
        roundTimeShowStyle.value = 'none'; 
    }
})

// 监视最新价格的变化，改变出价价格

/**
 * 从redis中根据id取竞拍时间戳，判断是否需要展示倒计时（不为null或距离现在秒数 > 0）
 * @param auctionInfo 当前选选中的竞品
 */
async function checkAddCountDownShow(auctionInfo: AuctionProduct){
    if(auctionInfo.uid == undefined){
        return false;
    }
    // 获取选中竞品ID的时间戳，转换为秒数进行判断
    let url: string = `${BASERUL}/auctionProducts/getCountDownById?auctionProductId=${auctionInfo.uid}`
    const {data: {data: coundDown}} = await axios.get(url);
    
    if(coundDown != null && (coundDown - moment(new Date()).valueOf())/ 1000 > 0){
        // 重新获取倒计时
        const countDownSecond: number =Math.floor((coundDown - moment(new Date()).valueOf())/ 1000);
        // openCountDown(coundDown - moment(new Date()).valueOf() / 1000);
        openCountDown(countDownSecond)
        // 展示倒计时
        roundTimeShowStyle.value = 'block';
        return;
    }
    roundTimeShowStyle.value = 'none'; 
}


/**
 * 竞拍后倒计时处理
 * @param coundDown 竞拍剩余秒数
 */
function openCountDown(coundDown: number){
    if(countDownTimer)
        clearInterval(countDownTimer)
        timeBySecond.value = coundDown
        countDownTimer = setInterval(()=>{
            timeBySecond.value--
            // 倒计时到了，竞拍拍卖成功
            if(timeBySecond.value <= 0){
                dealOk();
            }
        },1000)
}

/**
 * 成交逻辑（30秒倒计时后没人触发竞拍）
 */
async function dealOk(){
    if(countDownTimer)
    clearInterval(countDownTimer)
    roundTimeShowStyle.value = "none"
    isStartAuction.value = false;

    // 存储拍卖过程信息
    let myBlock = true;
    if(myBlock){
        myBlock = false;
        const myData = {userId:userStore.userInfo.uid, uid:auctionStore.auction_info.uid}
        const res = await axios.post(`${BASERUL}/auctionProducts/save`,myData)
        console.log(res);
        setTimeout(()=>{
            myBlock = true;
        }, 1000)
    }
}

/**
 * 获取所有竞品的map数据
 */
async function getAuctionProductMapData(){
    let url: string = `${inject('apiBaseUrl')}/auctionProducts/getAuctionTimeInfo`;
    const {data: {data: res}} = await axios.get(url);
    const mapData =  timestampToDate(res); // 调用自定义时间转换函数
    // 添加定时器
    checkAddTimer(mapData);
}

/**
 * 工具函数：遍历检查“拍卖时间”，当拍卖时间距离开拍时间小于30分钟，开启定时器。
 * @param mapData 处理好的的Map对象数据，key为id，value为时间
 */
function checkAddTimer(mapData: any): void{

    clearIntervalTool(); // 调用自定义清除定时器函数

    for (const key in mapData) {
        // 获取开拍距离现在的分钟数
        const auctionMinute =  (moment(new Date()).valueOf() - moment(mapData[key]).valueOf())/1000/60
        if(auctionMinute > 0){
            continue;
        }
        let targetMinute =  Math.abs(auctionMinute)
        if(targetMinute < 30){ // 距离开拍小于30分钟，开启定时器
            let mySecond = targetMinute * 60;
            const tempTimer = setInterval(()=>{
                checkTimerOver(key,  mySecond--, tempTimer)
            },1000)
            // 将定时器存储到列表中进行集中管理
            auctionTimerList.push(tempTimer);
        }
    }
}

/**
 * 竞拍触发器
 */
function auctionHandle(){

    let currentPrice:number = 0;
    if(auctionStore.newPriceObj.newPrice > 0){
        currentPrice = auctionStore.newPriceObj.newPrice;
    }else{
        currentPrice = auctionStore.auction_info.price;
    }
    
    if( parseInt(price.value) < parseInt(currentPrice) + auctionStore.auction_info.incrementPrice){
        ElMessage({
            message: '出价应高于【底价 + 加价幅度】',
            type:'warning'
        })
        return;
    }

    if(!isStartAuction.value){
        ElMessage('竞品暂未拍卖');
        return false;
    }

    ElMessage({
        message: '竞拍成功!',
        type:'success'
    })

    // 存储拍卖触发的竞品ID到本地存储，每次切换竞品用于判断。
    window.localStorage.setItem("aucProductId",auctionStore.auction_info.uid);
    // 存储用户是否点击过竞拍
    window.localStorage.setItem("isClick","yes");

    // 清除“流拍定时器”
    clearTimeout(notAuctionTimer);
    // 通知后端websocket实时通信
    if(mysocket){
        mysocket.send("auction");
    }
    
    // 存储redis缓存，存储拍卖信息和成交倒计时时间戳
    addAuctionInfoToRedis(auctionStore.auction_info);
    setTimeout(()=>{
        getbuyingPrice()
    }, 2000)
}

/**
 * 将成交倒计时信息存入redis中
 * @param auction_info 竞拍的竞品信息
 */
async function addAuctionInfoToRedis(auction_info: AuctionProduct){
    // 将拍卖成交时间戳存储到redis（id: 时间戳）
    let timestamp = moment(new Date).valueOf();
    const requirestData = new AUctionCount(auction_info.uid, timestamp + 30000);
    let url: string = `${BASERUL}/auctionProducts/addCountDownToRedis`;
    await axios.post(url,requirestData);
    // 将拍卖过程信息存储到redis（用户id， 竞品id，拍卖价格）
    const auctionInfoData = new AuctionInfo(userStore.userInfo.uid, auction_info.uid, price.value);
    let url1: string = `${BASERUL}/auctionProducts/addAuctionInfoToRedis`;
    const res = await axios.post(url1,auctionInfoData);
    // 判断返回检查后的价格
    console.log(res);
}

/**
 * 工具函数：判断定时器是否到时，到时间通知后端
 * @param id 竞品的id
 * @param timeSecond 剩余秒数
 */
async function checkTimerOver(id: string, timeSecond: number, timer: NodeJS.Timeout){
    // 判断是否是否到达拍卖时间（传入的秒数是否小于等于0）
    if(timeSecond <= 0){
        // 关闭定时器
        clearInterval(timer);
        // 通知后端修改数据库
        updateAuctionStatus(id, 1);
        // 前端重新获取竞品数据，开启10分钟流拍倒计时（修改pinia中状态，使数据重新获取）
        auctionStore.updateAuctionFlag(!auctionStore.auctionFlag);
        ElMessage({
            message: `有商品开始拍卖了\n竞品id是:${id}`,
            type: 'success',
        })

        // alert(`有商品开始拍卖了\n竞品id是:${id}`)
        // setTimeout(()=>{
        //     alert(`有商品开始拍卖了\n竞品id是:${id}`)
        // }, 2000)
        // 开启流拍倒计时
        notAuctionHandle(id);
    }
}

/**
 * 流拍计时器生成（10分钟）
 * @param id 竞品ID
 */
async function notAuctionHandle(id: string){
    // 将流拍的到期时间存储在本地存储（防止页面刷新定时器被刷掉）
    notAuctionTimer = setTimeout( async()=>{
        // 10分钟未触发拍卖，将此竞品的拍卖时间修改为明日的同一时间
        updateAuctionStatus(id, 0);
        // 通知页面修改
        auctionStore.updateNotAuctionFlag(!auctionStore.notAuctionFlag);
    },10*60*1000)
    const storageData = window.localStorage.getItem('timeOuts');
    
    // 获取10分钟后的时间戳，并存储到localStoryge
    const timestamp = moment().add(10, 'minutes').valueOf()

    if(storageData != null){
        const parsedData = JSON.parse(storageData);
        parsedData.push(new MyLocalStorage(id,timestamp));
        // 转存
        window.localStorage.setItem('timeOuts',JSON.stringify(parsedData))
    }
    
    window.localStorage.setItem("timeOuts",JSON.stringify([new MyLocalStorage(id,timestamp)]))
    
}

/**
 * 修改数据库竞品拍卖状态
 * @param id 竞品ID
 * @param status 竞品状态
 */
async function updateAuctionStatus(id: string, status: number){
    const requireData = new AuctionProduct();
    requireData.setUid(id);
    requireData.setStatus(status);
    await axios.put(`http://localhost:8957/auctionProducts/updateStatus`, requireData);

}

/**
 * 清除定时器
 */
function clearIntervalTool(){
    for (const item of auctionTimerList) {
        clearInterval(item)
    }
}


/**
 * 工具函数：遍历对象的value值，将时间戳转为日期时间格式
 * @param targetObj 后端返回的Map数据
 * @return 返回处理好的对象【id：日期时间】
 */
function timestampToDate(targetObj: any): Object{
    for (const key in targetObj) {
        targetObj[key] = new Date(targetObj[key]); 
    }
    return targetObj;
}

/**
 * 获取本地存储，重新开启流拍定时器
 */
function getLocalStorageTimeOut(){
    const storageData = window.localStorage.getItem('timeOuts');
    if(storageData != null){
        const parsedData = JSON.parse(storageData);
        for (const item of parsedData) {
            const myTime =  (item.timestamp - moment().valueOf()) / 1000
            if(myTime <= 0){
                continue;
            }
            // 循环添加定时器
            setTimeout(()=>{
                updateAuctionStatus(item.id, 0);
                auctionStore.updateNotAuctionFlag(!auctionStore.notAuctionFlag);
            }, myTime *1000)
        }
    }
}

/**
 * 连接WebSocket
 */
async function linkWebSocket(){
    // 创建连接
    mysocket = new WebSocketService("ws://localhost:8957/myWebSocket");
    // 监听拍卖
    // let myMsg = await mysocket.getMessage()
    // if(myMsg){
    //     console.log("接收到的消息:", myMsg.data);
    // }
}


onMounted(() => {
    return () => {
        if(mysocket)
        mysocket.close()
    };
});

</script>

<style scoped>

#roundTimeShow{
    position: absolute;
    top: 10px;
    right: 30px;
    width: 200px;
    height: 200px;
    /* border: solid black 2px; */
    border-radius: 50%;
    box-shadow: 0px 0px 10px #000;
    background-color: #e8858532;
    display: flex;
    justify-content: center;
    align-items: center;
}

#timeSecondNumber{
    color: red;
    font-size: 35px;
}

#auction_img{
    display: flex;
    justify-content: center;
    align-items: center;
}

#my_picture{
    width: 300px;
    border-radius: 10px; 
}

#papapa{
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 30px;
}

#papapa button{
    border: none;
    border-radius: 10px;
    color: rgb(241, 54, 54);
    font-weight: 800;
    font-size: 20px;
    height: 58px;
    width: 130px;
}

#papapa button:hover{
    background-color: #fff;
}

#hotIcon{
    width: 50px;
    position: relative;
    top: 5px;
}

#auction_price, #buying_price{
    margin: 0 auto;
    margin-top: 40px;
    width: 50%;
    text-align: center;
    color: white;
    font-weight: 700;
    font-size: 20px;
    position: relative;
    border-bottom: solid rgb(241, 241, 241);
}

#cj{
    position: absolute;
    left: -55px;
}

#dqj{
    position: absolute;
    left: -75px;
}

#dqj_price{
    color: #e66666;
}

#buying_price_ipt{
    background: none;
    border: none;
    height: 25px;
    text-align: center;
    font-size: 20px;
    width: 100px;
    color: rgb(246, 191, 191);
    font-weight: 800;
}


#container{
    display: flex;
    height: 100%;
    width: 100%;
    justify-content: space-between;
    overflow: hidden;
}

#auctionBox{
    margin: 0 auto;
    width: 60%;
    height: 90%;
}

#content{
    width: 50%;
    box-shadow: 0px 0px 10px #89483d;
    border-radius: 5px;
    height: 95%;
    backdrop-filter: blur(5px);
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
}

#tip{
    position: absolute;
    left: 0px;
    top: 10px;
    /* border: solid red 2px; */
    background-color: #82b8d8;
    padding: 10px;
    color: rgb(202, 70, 70);
    font-weight: 700;
    border-radius: 20px;
}

#tip1{
    position: absolute;
    left: 0px;
    top: 10px;
    padding-left: 10px;
}

#mainContent{
    width: 85%;
    white-space:pre-wrap;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background: url("http://localhost:8957/commons/download?picName=mainBK.jpg") no-repeat center center;
    background-size:cover;
    border-radius: 5px;
    position: relative;
}

#right_aside{
    width: 15%;
    height: 100%;
    box-shadow: 0px 0px 5px #2d2b2b;
    border-radius: 10px;
}
.notAuctionStyle{
    background-color: #ccc;
    cursor: not-allowed;
}

.AuctionStyle{
    cursor: pointer;
}
</style>